package uz.rt.dicom.uid;

import java.nio.ByteOrder;

/**
 * Transfer Syntax is used in DICOM to describe the DICOM file format and the network transfer methods.
 * The following properties are stored in the Transfer Syntax:
 * <ul>
 * <li>Value representation: Implicit / Explicit</li>
 * <li>Byte order: Little / Big Endian</li>
 * <li>Pixel data compression</li>
 * </ul>
 */
public class TransferSyntax extends Uid
{
// ------------------------------ FIELDS ------------------------------

    public final static TransferSyntax ImplicitVRLittleEndian = new TransferSyntax("1.2.840.10008.1.2",
                                                                                   "Implicit VR Little Endian", false,
                                                                                   ByteOrder.LITTLE_ENDIAN, false);
    public final static TransferSyntax Default = ImplicitVRLittleEndian;
    public final static TransferSyntax ExplicitVRLittleEndian = new TransferSyntax("1.2.840.10008.1.2.1",
                                                                                   "Explicit VR Little Endian", true,
                                                                                   ByteOrder.LITTLE_ENDIAN, false);
    public final static TransferSyntax DeflatedExplicitVRLittleEndian = new TransferSyntax("1.2.840.10008.1.2.1.99",
                                                                                           "Deflated Explicit VR Little Endian",
                                                                                           true,
                                                                                           ByteOrder.LITTLE_ENDIAN,
                                                                                           false, true);
    public final static TransferSyntax ExplicitVRBigEndian = new TransferSyntax("1.2.840.10008.1.2.2",
                                                                                "Explicit VR Big Endian", true,
                                                                                ByteOrder.BIG_ENDIAN, false);
    public final static TransferSyntax JPEGBaseline_1 = new TransferSyntax("1.2.840.10008.1.2.4.50",
                                                                           "JPEG Baseline (Process 1): Default Transfer Syntax for Lossy JPEG 8 Bit Image Compression",
                                                                           true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGExtended_2_4 = new TransferSyntax("1.2.840.10008.1.2.4.51",
                                                                             "JPEG Extended (Process 2 & 4): Default Transfer Syntax for Lossy JPEG 12 Bit Image Compression",
                                                                             true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGExtended_3_5 = new TransferSyntax("1.2.840.10008.1.2.4.52",
                                                                             "JPEG Extended (Process 3 & 5) (Retired)",
                                                                             true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGSpectral_6_8 = new TransferSyntax("1.2.840.10008.1.2.4.53",
                                                                             "JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) (Retired)",
                                                                             true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGSpectral_7_9 = new TransferSyntax("1.2.840.10008.1.2.4.54",
                                                                             "JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9)(Retired)",
                                                                             true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGFullProgression_10_12 = new TransferSyntax("1.2.840.10008.1.2.4.55",
                                                                                      "JPEG Full Progression, Non-Hierarchical (Process 10 & 12)(Retired)",
                                                                                      true, ByteOrder.LITTLE_ENDIAN,
                                                                                      true);
    public final static TransferSyntax JPEGFullProgression_11_13 = new TransferSyntax("1.2.840.10008.1.2.4.56",
                                                                                      "JPEG Full Progression, Non-Hierarchical (Process 11 & 13)(Retired)",
                                                                                      true, ByteOrder.LITTLE_ENDIAN,
                                                                                      true);
    public final static TransferSyntax JPEGLossless_14 = new TransferSyntax("1.2.840.10008.1.2.4.57",
                                                                            "JPEG Lossless, Non-Hierarchical (Process 14)",
                                                                            true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGLossless_15 = new TransferSyntax("1.2.840.10008.1.2.4.58",
                                                                            "JPEG Lossless, Non-Hierarchical (Process 15) (Retired)",
                                                                            true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGExtended_16_18 = new TransferSyntax("1.2.840.10008.1.2.4.59",
                                                                               "JPEG Extended, Hierarchical (Process 16 & 18) (Retired)",
                                                                               true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGExtended_17_19 = new TransferSyntax("1.2.840.10008.1.2.4.60",
                                                                               "JPEG Extended, Hierarchical (Process 17 & 19) (Retired)",
                                                                               true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGSpectral_20_22 = new TransferSyntax("1.2.840.10008.1.2.4.61",
                                                                               "JPEG Spectral Selection, Hierarchical (Process 20 & 22) (Retired)",
                                                                               true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGSpectral_21_23 = new TransferSyntax("1.2.840.10008.1.2.4.62",
                                                                               "JPEG Spectral Selection, Hierarchical (Process 21 & 23) (Retired)",
                                                                               true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGFullProgression_24_26 = new TransferSyntax("1.2.840.10008.1.2.4.63",
                                                                                      "JPEG Full Progression, Hierarchical (Process 24 & 26) (Retired)",
                                                                                      true, ByteOrder.LITTLE_ENDIAN,
                                                                                      true);
    public final static TransferSyntax JPEGFullProgression_25_27 = new TransferSyntax("1.2.840.10008.1.2.4.64",
                                                                                      "JPEG Full Progression, Hierarchical (Process 25 & 27)(Retired)",
                                                                                      true, ByteOrder.LITTLE_ENDIAN,
                                                                                      true);
    public final static TransferSyntax JPEGLossless_28 = new TransferSyntax("1.2.840.10008.1.2.4.65",
                                                                            "JPEG Lossless, Hierarchical (Process 28) (Retired)",
                                                                            true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGLossless_29 = new TransferSyntax("1.2.840.10008.1.2.4.66",
                                                                            "JPEG Lossless, Hierarchical (Process 29) (Retired)",
                                                                            true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEGLossless_14_FirstOrder = new TransferSyntax("1.2.840.10008.1.2.4.70",
                                                                                       "JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14)",
                                                                                       true, ByteOrder.LITTLE_ENDIAN,
                                                                                       true);
    public final static TransferSyntax JPEG_LS_LossLess = new TransferSyntax("1.2.840.10008.1.2.4.80",
                                                                             "JPEG-LS Lossless Image Compression", true,
                                                                             ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEG_LS_Lossy = new TransferSyntax("1.2.840.10008.1.2.4.81",
                                                                          "JPEG-LS Lossy (Near-Lossless) Image Compression",
                                                                          true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEG_2000_LossLess = new TransferSyntax("1.2.840.10008.1.2.4.90",
                                                                               "JPEG 2000 Image Compression (Lossless Only)",
                                                                               true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEG_2000 = new TransferSyntax("1.2.840.10008.1.2.4.91",
                                                                      "JPEG 2000 Image Compression", true,
                                                                      ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPEG_2000_LossLess_P2_0 = new TransferSyntax("1.2.840.10008.1.2.4.92",
                                                                                    "JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only)",
                                                                                    true, ByteOrder.LITTLE_ENDIAN,
                                                                                    true);
    public final static TransferSyntax JPEG_2000_LossLess_P2_1 = new TransferSyntax("1.2.840.10008.1.2.4.93",
                                                                                    "JPEG 2000 Part 2 Multi-component Image Compression",
                                                                                    true, ByteOrder.LITTLE_ENDIAN,
                                                                                    true);
    public final static TransferSyntax JPIP_Referenced = new TransferSyntax("1.2.840.10008.1.2.4.94", "JPIP Referenced",
                                                                            true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax JPIP_ReferencedDeflate = new TransferSyntax("1.2.840.10008.1.2.4.95",
                                                                                   "JPIP Referenced Deflate", true,
                                                                                   ByteOrder.LITTLE_ENDIAN, true, true);
    public final static TransferSyntax MPEG2_MPML = new TransferSyntax("1.2.840.10008.1.2.4.100",
                                                                       "MPEG2 Main Profile Main Level", true,
                                                                       ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax MPEG2_MPHL = new TransferSyntax("1.2.840.10008.1.2.4.101",
                                                                       "MPEG2 Main Profile High Level", true,
                                                                       ByteOrder.LITTLE_ENDIAN, true);
    @SuppressWarnings({"HardcodedFileSeparator", "HardcodedFileSeparator"})
    public final static TransferSyntax MPEG4_264HP = new TransferSyntax("1.2.840.10008.1.2.4.102",
                                                                        "MPEG-4 AVC/H.264 High Profile", true,
                                                                        ByteOrder.LITTLE_ENDIAN, true);
    @SuppressWarnings({"HardcodedFileSeparator", "HardcodedFileSeparator"})
    public final static TransferSyntax MPEG4_264BDHP = new TransferSyntax("1.2.840.10008.1.2.4.103",
                                                                          "MPEG-4 AVC/H.264 BDcompatible High Profile / Level 4.1",
                                                                          true, ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax RLE_Lossless = new TransferSyntax("1.2.840.10008.1.2.5", "RLE Lossless", true,
                                                                         ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax RFC2557_MIME = new TransferSyntax("1.2.840.10008.1.2.6.1",
                                                                         "RFC 2557 MIME encapsulation", true,
                                                                         ByteOrder.LITTLE_ENDIAN, true);
    public final static TransferSyntax XML_Encoding = new TransferSyntax("1.2.840.10008.1.2.6.2", "XML Encoding", true,
                                                                         ByteOrder.LITTLE_ENDIAN, true);

    /** Byte order specifying if Little or Big Endian is used */
    private ByteOrder byteOrder;
    /** True if the transfer syntax encapsulates pixel data */
    private boolean encapsulatePixel;
    /** True if the transfer syntax uses explicit value representation */
    private boolean explicitVR;
    /** True if the transfer syntax uses a deflate compression */
    private boolean deflated;

// --------------------------- CONSTRUCTORS ---------------------------

    /**
     * Create a transfer syntax based on a UID and a name.
     *
     * @param uid  Unique identifier
     * @param name Name of the transfer syntax
     */
    public TransferSyntax(String uid, String name)
    {
        super(uid, name, UidType.TRANSFER_SYNTAX);
    }

    /**
     * Create a transfer syntax based on a UID and a name while specifying the byte order in which the transfer is done
     * as well as the encapsulation of pixel data.
     *
     * @param uid              Unique identifier
     * @param name             Name of the transfer syntax
     * @param explicitVR       True if explicit value representation is used
     * @param byteOrder        Little or Big Endian byte order
     * @param encapsulatePixel True if pixel data is encapsulated.
     */
    public TransferSyntax(String uid, String name, boolean explicitVR, ByteOrder byteOrder, boolean encapsulatePixel)
    {
        super(uid, name, UidType.TRANSFER_SYNTAX);
        this.explicitVR = explicitVR;
        this.byteOrder = byteOrder;
        this.encapsulatePixel = encapsulatePixel;
        this.deflated = false;
    }

    /**
     * Create a transfer syntax based on a UID and a name while specifying the byte order in which the transfer is done
     * as well as the encapsulation of pixel data.
     *
     * @param uid              Unique identifier
     * @param name             Name of the transfer syntax
     * @param explicitVR       True if explicit value representation is used
     * @param byteOrder        Little or Big Endian byte order
     * @param encapsulatePixel True if pixel data is encapsulated.
     * @param deflated         True if the transfer syntax uses a deflate compression
     */
    public TransferSyntax(String uid, String name, boolean explicitVR, ByteOrder byteOrder, boolean encapsulatePixel,
                          boolean deflated)
    {
        super(uid, name, UidType.TRANSFER_SYNTAX);
        this.explicitVR = explicitVR;
        this.byteOrder = byteOrder;
        this.encapsulatePixel = encapsulatePixel;
        this.deflated = deflated;
    }

// --------------------- GETTER / SETTER METHODS ---------------------

    /**
     * Get the byte order at which the transfer syntax is defined.
     *
     * @return Little or Big Endian byte order
     */
    public ByteOrder getByteOrder()
    {
        return byteOrder;
    }

    /**
     * Does the transfer syntax use a deflate compression?
     *
     * @return True if the transfer syntax uses a deflate compression.
     */
    public boolean isDeflated()
    {
        return deflated;
    }

    /**
     * Is pixel data encapsulated in the transfer syntax?
     *
     * @return True if pixel data is encapsulated.
     */
    public boolean isEncapsulatePixel()
    {
        return encapsulatePixel;
    }

    /**
     * Is explicit value representation used in the transfer syntax.
     *
     * @return True if explicit value representation is used.
     */
    public boolean isExplicitVR()
    {
        return explicitVR;
    }

// ------------------------ CANONICAL METHODS ------------------------

    @Override
    public boolean equals(Object o)
    {
        if (this == o) return true;
        if (!(o instanceof TransferSyntax)) return false;

        TransferSyntax that = (TransferSyntax) o;

        return deflated == that.deflated && encapsulatePixel == that.encapsulatePixel && explicitVR == that.explicitVR && !(byteOrder != null ? !byteOrder
                .equals(that.byteOrder) : that.byteOrder != null);
    }

    @Override
    public int hashCode()
    {
        int result = byteOrder != null ? byteOrder.hashCode() : 0;
        result = 31 * result + (encapsulatePixel ? 1 : 0);
        result = 31 * result + (explicitVR ? 1 : 0);
        result = 31 * result + (deflated ? 1 : 0);
        return result;
    }
}
